package org.agony2d.view.core
{
	import flash.display.DisplayObject;
	import flash.display.DisplayObjectContainer;
	import flash.display.Sprite;
	import flash.display.Stage;
	import flash.events.MouseEvent;
	import flash.geom.Point;
	import flash.geom.Rectangle;
	import flash.system.Capabilities;
	import flash.ui.Mouse;
	import org.agony2d.control.MouseManager;
	
	import org.agony2d.Agony;
	import org.agony2d.notify.Observer;
	import org.agony2d.core.ProcessManager;
	import org.agony2d.core.agony_internal;
	import org.agony2d.debug.Logger;
	import org.agony2d.view.core.Component;
	import org.agony2d.view.core.IComponent;
	import org.agony2d.view.core.AgonySprite;
	import org.agony2d.notify.AEvent;
	import org.agony2d.view.puppet.supportClasses.PuppetComp;
	import org.agony2d.view.supportClasses.AbstractButton;

	use namespace agony_internal;
	
final public class UIManager
{

	public function UIManager()
	{
		m_mouse = MouseManager.getInstance()
		m_mouse.leftButton.addEventListener(AEvent.PRESS,   ____onMouseStateChange, false, PRIORITY)
		m_mouse.leftButton.addEventListener(AEvent.RELEASE, ____onMouseStateChange, false, PRIORITY)
		m_mouse.addEventListener(AEvent.MOVE,               ____onMouseStateChange, false, PRIORITY)
		m_mouse.addEventListener(AEvent.DOUBLE_CLICK,       ____onMouseStateChange, false, PRIORITY)
		
		m_interactive = true
		m_monitor = new Sprite()
		m_monitor.mouseEnabled  =  m_monitor.mouseChildren  =  false
		m_monitor.tabEnabled    =  m_monitor.tabChildren    =  false
		m_stage.addChildAt(m_monitor, 0)
		
	}
	
	agony_internal static function get hoveredElement()  : IComponent { return getProxy(m_hoveredCid) }
	
	agony_internal static function get pressedElement()  : IComponent { return getProxy(m_pressedCid) }
	
	agony_internal static function getProxy( cid:uint ) : IComponent
	{
		var c:Component = m_registeredCompList[cid];
		return c ? c.m_proxy as IComponent : null;
	}
	
	agony_internal static function reset() : void
	{
		var element:IComponent
		
		element = hoveredElement
		if (element && element.fusion is AbstractButton)
		{
			(element.fusion as AbstractButton).resetButton()
		}
		element = pressedElement
		if (element && element.fusion is AbstractButton)
		{
			(element.fusion as AbstractButton).resetButton()
		}
	}
	
	agony_internal static function registerComp( comp:Component ) : void
	{
		m_registeredCompList[++m_numRegistered]  =  comp;
		comp.m_cid                               =  m_numRegistered;
	}
	
	agony_internal static function unregisterComp( comp:Component ) : void
	{
		delete m_registeredCompList[comp.m_cid]
	}
	
	agony_internal function addModule( moduleName:String, stateType:Class ) : void
	{
		if (m_moduleList[moduleName])
		{
			Logger.reportError('UIManager', 'addModule', 'existed module: ' + moduleName)
		}
		m_moduleList[moduleName] = new ModuleProp(stateType)
	}
	
	agony_internal function getModule( moduleName:String ) : IModule
	{
		return m_moduleList[moduleName]
	}
	
	agony_internal function killAllModules() : void
	{
		var key:*
		var module:ModuleProp
		
		for (key in m_moduleList)
		{
			module = m_moduleList[key]
			if (module.m_multiFusion)
			{
				module.close()
			}
		}
	}
	
	
	agony_internal static const PRIORITY:int = 800 	// 触碰优先级
	agony_internal static var m_registeredCompList:Vector.<Component> = new Vector.<Component>(44444, true);
	agony_internal static var m_numRegistered:int;
	agony_internal static var cachedPoint:Point = new Point();
	agony_internal static var m_stage:Stage
	agony_internal static var m_monitor:Sprite
	agony_internal static var m_hoveredCid:uint, m_pressedCid:uint
	agony_internal static var m_invalidWhenLeave:Boolean, m_interactive:Boolean
	
	agony_internal var m_nullPressedObserver:Observer
	agony_internal var m_moduleList:Object = new Object()
	agony_internal var m_mouse:MouseManager
	
	
	/** 更新交互状态
	 *  @usage	按下组件，再滑出组件，此时按下动作失效.
	 */
	final private function ____onMouseStateChange( event:AEvent ) : void
	{
		var PT:PuppetComp, oldPT:PuppetComp;
		var cid:uint, l:int
		var target:DisplayObject
		var parent:DisplayObjectContainer
		var type:String = event.type
		var objectList:Array
		
		if (!m_interactive)
		{
			return
		}
		cachedPoint.x  =  m_mouse.stageX
		cachedPoint.y  =  m_mouse.stageY
		objectList     =  m_monitor.getObjectsUnderPoint(cachedPoint)
		l              =  objectList.length
		
		// debug !!
		//trace(type + ' | ' + objectList)
		
		while (--l > -1)
		{
			target  =  objectList[l];
			parent  =  target.parent
			while (parent && !Boolean(parent is AgonySprite))
			{
				parent = parent.parent
			}
			PT = parent as PuppetComp
			// 外部显示对象
			if (!PT)
			{
				event.stopImmediatePropagation()
				break
			}
			if (PT.interactiveZ)
			{
				// 停止传播
				event.stopImmediatePropagation()
				switch(type)
				{
					case AEvent.PRESS:
						m_hoveredCid = m_pressedCid = PT.m_cid
						PT.bubble(AEvent.PRESS)
						//Logger.reportMessage(this, 'press' + ' | ' + objectList)
						return;
						
					case AEvent.RELEASE:
						cid           =  m_pressedCid
						m_pressedCid  =  m_hoveredCid = 0
						oldPT         =  m_registeredCompList[cid] as PuppetComp
						if (oldPT && oldPT.interactiveZ)
						{
							oldPT.bubble(AEvent.RELEASE)
						}
						else if (PT != oldPT)
						{
							PT.bubble(AEvent.RELEASE)
						}
						//Logger.reportMessage(this, 'release' + ' | ' + objectList)
						if (PT.m_cid == cid)
						{
							PT.bubble(AEvent.CLICK)
							//Logger.reportMessage(this, 'click' + ' | ' + objectList)
						}
						return;
						
					case AEvent.MOVE:
						cid = PT.m_cid
						if (cid != m_hoveredCid)
						{
							if (m_hoveredCid > 0)
							{
								if (cid == m_pressedCid && m_invalidWhenLeave)
								{
									m_pressedCid = 0
								}
								oldPT = m_registeredCompList[m_hoveredCid] as PuppetComp
								if (oldPT && oldPT.interactiveZ && oldPT.stage)
								{
									m_hoveredCid = 0
									oldPT.bubble(AEvent.LEAVE)
								}
							}
							m_hoveredCid = cid
							PT.bubble(AEvent.OVER)
						}
						PT.bubble(AEvent.MOVE)
						return;
						
					case AEvent.DOUBLE_CLICK:
						PT.bubble(AEvent.DOUBLE_CLICK)
						return;
				}
			}
		}
		if (type == AEvent.MOVE && m_hoveredCid > 0)
		{
			oldPT         =  m_registeredCompList[m_hoveredCid] as PuppetComp;
			m_hoveredCid  =  0
			if (oldPT && oldPT.interactiveZ && oldPT.stage)
			{
				oldPT.bubble(AEvent.LEAVE)
			}
			if (m_pressedCid > 0 && m_invalidWhenLeave)
			{
				m_pressedCid = 0
			}
		}
		else if (type == AEvent.PRESS && m_nullPressedObserver)
		{
			m_nullPressedObserver.execute()
		}
		else if(type == AEvent.RELEASE && m_pressedCid > 0)
		{
			oldPT         =  m_registeredCompList[m_pressedCid] as PuppetComp;
			m_pressedCid  =  0;
			if (oldPT && oldPT.interactiveZ && oldPT.stage)
			{
				oldPT.bubble(AEvent.RELEASE)
			}
		}
	}
}
}
import flash.events.EventDispatcher;
import org.agony2d.notify.AEvent;
import org.agony2d.notify.Notifier;

import org.agony2d.core.INextUpdater;
import org.agony2d.core.NextUpdaterManager;
import org.agony2d.core.ProcessManager;
import org.agony2d.core.agony_internal;
import org.agony2d.view.MultiFusion;
import org.agony2d.view.core.IModule;
import org.agony2d.view.core.UIManager;
use namespace agony_internal;
	
final class ModuleProp extends Notifier implements IModule, INextUpdater
{
	
	public function ModuleProp( stateType:Class )
	{
		super(null)
		m_stateType = stateType
	}
	
	final public function get closed():Boolean
	{
		return m_multiFusion && m_multiFusion.displayObject.stage
	}
	
	final public function popup( layer:int = -1, immediate:Boolean = true, stateArgs:Array = null ) : void
	{
		m_layer = layer
		mStateArgs = stateArgs
		if (immediate)
		{
			if (!m_closed)
			{
				NextUpdaterManager.removeNextUpdater(this)
				m_closed = true
			}
			this.modify()
		}
		else if (m_closed)
		{
			NextUpdaterManager.addNextUpdater(this)
			m_closed = false
		}
	}
	
	final public function close( destroy:Boolean = true ) : void
	{
		if (!m_closed)
		{
			NextUpdaterManager.removeNextUpdater(this)
			m_closed = true
		}
		if (!m_multiFusion)
		{
			return
		}
		if (destroy)
		{
			m_multiFusion.kill()
			m_multiFusion = null
		}
		else
		{
			UIManager.m_monitor.removeChild(m_multiFusion.displayObject)
		}
		this.dispatchDirectEvent(AEvent.EXIT_STAGE)
	}
	
	public function modify() : void
	{
		if (!m_multiFusion)
		{
			m_multiFusion = new MultiFusion()
		}
		if (m_layer == -1)
		{
			UIManager.m_monitor.addChild(m_multiFusion.displayObject)
		}
		else
		{
			UIManager.m_monitor.addChildAt(m_multiFusion.displayObject,UIManager.m_monitor.numChildren + m_layer + 1)
		}
		m_multiFusion.setState(m_stateType, mStateArgs)
		this.dispatchDirectEvent(AEvent.ENTER_STAGE)
		mStateArgs = null
		m_closed = true
	}
	
	internal var m_stateType:Class
	internal var m_multiFusion:MultiFusion
	internal var mStateArgs:Array
	internal var m_layer:int
	internal var m_closed:Boolean = true
}